﻿using HenuAlbum.ControllerModels;
using HenuAlbum.DbContext;
using HenuAlbum.Identity;
using HenuAlbum.Models;
using HenuAlbum.ResponseModels;
using HenuAlbum.Utils;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Cors;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;

namespace HenuAlbum.Controllers
{

    [ApiController]
    [Route("api/[controller]")]
    public class PersonalAlbumController : ControllerBase
    {
        private readonly AppDbContext _appDbContext;

        private readonly UserManager<User> _userManager;

        public PersonalAlbumController(AppDbContext appDbContext, UserManager<User> userManager)
        {
            _appDbContext = appDbContext;
            _userManager = userManager;
        }


        [HttpGet("Query")]
        public async Task<IActionResult> Query(int? collegeId, int? majorId, int? classId, int? gradeId, int limit = 20, int page = 1)
        {
            Tools.ResolveLimitAndPage(ref limit, ref page, 20, 100);
            var list = await _appDbContext.PersonalAlbums
                    .AsNoTracking()
                    .Include(x => x.Class)
                    .ThenInclude(x => x.Major)
                    .ThenInclude(x => x.College)
                    .Where(x => x.IsPublic && x.ReviewState == ReviewState.Reviewed &&
                            (classId == null ? true : x.ClassId == classId) &&
                            (gradeId == null ? true : x.Class.GradeId == gradeId) &&
                            (majorId == null ? true : x.Class.MajorId == majorId) &&
                            (collegeId == null ? true : x.Class.Major.CollegeId == collegeId))
                    .OrderBy(x => x.Id)
                    .Skip(limit * (page - 1))
                    .Take(limit)
                    .ToListAsync();
            return Ok(new ArrayResponse(list.Select((x) =>
            {
                var r = _appDbContext.Resources
                    .Where(t => t.AlbumId == x.Id)
                    .Select(r => new { r.Id, r.DownloadCount })
                    .FirstOrDefault();
                int likeCount = _appDbContext.UserLikeAlbum.Count(y => y.AlbumId == x.Id);
                return new
                {
                    x.Id,
                    x.Title,
                    x.Description,
                    x.IsPublic,
                    x.CreatorId,
                    Coverid = r?.Id,
                    LikeCount = likeCount,
                    DownloadCount = r?.DownloadCount
                };
            }).ToList()));
        }

        [HttpGet("Unreviewed")]
        [Authorize(Roles = "管理员, 辅导员")]
        public async Task<IActionResult> GetUnReviewedAlbums(int? collegeId, int? majorId, int? gradeId, ReviewState reviewState = ReviewState.Unreviewed, int limit = 20, int page = 1)
        {
            Tools.ResolveLimitAndPage(ref limit, ref page, 20, 100);
            var list = await _appDbContext.PersonalAlbums
                    .AsNoTracking()
                    .Include(x => x.Creator)
                    .Include(x => x.Class)
                    .ThenInclude(x => x.Major)
                    .ThenInclude(x => x.College)
                    .Where(x => x.ReviewState == reviewState &&
                            (gradeId == null ? true : x.Class.GradeId == gradeId) &&
                            (majorId == null ? true : x.Class.MajorId == majorId) &&
                            (collegeId == null ? true : x.Class.Major.CollegeId == collegeId))
                    .Select(x => new
                    {
                        x.Id,
                        x.Title,
                        x.Description,
                        x.IsPublic,
                        x.CreatorId,
                        x.CreateTime,
                        CreatorFullName = x.Creator.FullName,
                        CreatorUserName = x.Creator.UserName
                    })
                    .OrderBy(x => x.Id)
                    .Skip(limit * (page - 1))
                    .Take(limit)
                    .ToListAsync();
            return Ok(new ArrayResponse(list));
        }

        [HttpPost("{albumId}/MarkReviewed")]
        [Authorize(Roles = "管理员, 辅导员")]
        public async Task<IActionResult> MarkReviewed(int albumId)
        {
            var album = await _appDbContext.PersonalAlbums
                .Where(x => x.Id == albumId)
                .FirstOrDefaultAsync();
            if (album == null) return BadRequest(new NotExistsError("相册不存在"));

            album.ReviewState = ReviewState.Reviewed;
            await _appDbContext.SaveChangesAsync();
            return Ok(new OkResponse());
        }

        [HttpPost("{albumId}/MarkUnreviewed")]
        [Authorize(Roles = "管理员, 辅导员")]
        public async Task<IActionResult> MarkUnreviewed(int albumId)
        {
            var album = await _appDbContext.PersonalAlbums
                .Where(x => x.Id == albumId)
                .FirstOrDefaultAsync();
            if (album == null) return BadRequest(new NotExistsError("相册不存在"));

            album.ReviewState = ReviewState.Unreviewed;
            await _appDbContext.SaveChangesAsync();
            return Ok(new OkResponse());
        }

        [HttpPost("{albumId}/MarkFailed")]
        [Authorize(Roles = "管理员, 辅导员")]
        public async Task<IActionResult> MarkFailed(int albumId)
        {
            var album = await _appDbContext.PersonalAlbums
                .Where(x => x.Id == albumId)
                .FirstOrDefaultAsync();
            if (album == null) return BadRequest(new NotExistsError("相册不存在"));

            album.ReviewState = ReviewState.Failed;
            await _appDbContext.SaveChangesAsync();
            return Ok(new OkResponse());
        }

        [HttpGet("GetByCreatorId")]
        public async Task<IActionResult> GetByCreatorId(int creatorId)
        {
            var userIdStr = User.FindFirstValue(ClaimTypes.NameIdentifier);

            var list = await _appDbContext.PersonalAlbums
                .AsNoTracking()
                .Include(x => x.Class)
                .Where(x => x.CreatorId == creatorId)
                .Select(x => new { x.Id, x.Title, x.Description, x.IsPublic, x.CreatorId, x.Class, x.ReviewState })
                .ToListAsync();

            if (userIdStr == null)
            {
                // 未登录用户只能访问已公开相册，删除所有未公开相册或未审核相册
                list.RemoveAll(x => !x.IsPublic || x.ReviewState != ReviewState.Reviewed);
            }
            else
            {
                var userId = int.Parse(userIdStr);

                if (User.IsInRole("辅导员"))
                {
                    //  do nothing...
                }
                else if (User.IsInRole("辅导员"))
                {
                    // 辅导员只可访问自己管理专业下的非公开相册
                    var managedMajors = await _appDbContext.Users
                        .AsNoTracking()
                        .Where(x => x.Id == userId)
                        .Select(x => x.ManagedMajors)
                        .FirstOrDefaultAsync();
                    list.RemoveAll(x => !managedMajors.Any(t => t.Id == x.Class.MajorId));
                }
                else if (userId != creatorId)
                {
                    // 其他用户只能访问自己创建的非公开相册，删除所有未公开相册或未审核相册
                    list.RemoveAll(x => !x.IsPublic || x.ReviewState != ReviewState.Reviewed);
                }
            }

            return Ok(new ArrayResponse(list.Select(x => new
            {
                x.Id,
                x.Title,
                x.Description,
                x.IsPublic,
                x.ReviewState
            }).ToList()));
        }

        [HttpGet]
        [Authorize]
        public async Task<IActionResult> GetMyAlbums(int limit = 20, int page = 1)
        {
            Tools.ResolveLimitAndPage(ref limit, ref page, 20, 100);
            var userId = int.Parse(User.FindFirstValue(ClaimTypes.NameIdentifier));
            var list = await _appDbContext.PersonalAlbums
                        .AsNoTracking()
                        .Where(x => x.CreatorId == userId)
                        .OrderBy(x => x.Id)
                        .Skip(limit * (page - 1))
                        .Take(limit)
                        .ToListAsync();
            return Ok(new ArrayResponse(list.Select((x) =>
            {
                var r = _appDbContext.Resources
                    .Where(t => t.AlbumId == x.Id)
                    .Select(r => new { r.Id, r.DownloadCount })
                    .FirstOrDefault();
                int likeCount = _appDbContext.UserLikeAlbum.Count(y => y.AlbumId == x.Id);
                return new
                {
                    x.Id,
                    x.Title,
                    x.Description,
                    x.IsPublic,
                    x.CreatorId,
                    x.ReviewState,
                    Coverid = r?.Id,
                    LikeCount = likeCount,
                    DownloadCount = r?.DownloadCount
                };
            }).ToList()));
        }

        [HttpGet("{albumId}")]
        public async Task<IActionResult> Details(int albumId)
        {
            // 对于非公开相册，辅导员、管理员的访问权限不同
            var userIdStr = User.FindFirstValue(ClaimTypes.NameIdentifier);

            var album = await _appDbContext.PersonalAlbums
                    .AsNoTracking()
                    .Include(x => x.Class)
                    .Where(x => x.Id == albumId)
                    .Select(x => new
                    {
                        x.Id,
                        x.Title,
                        x.Description,
                        x.IsPublic,
                        x.CreatorId,
                        x.Class,
                        x.ReviewState
                    })
                    .FirstOrDefaultAsync();

            if (album == null)
            {
                return BadRequest(new NotExistsError("相册不存在!"));
            }

            // 如果相册不是公开的或者没通过审核, 要根据角色判断是否可读:
            // 1.对于未登录用户，不可访问
            if (userIdStr == null && (!album.IsPublic || album.ReviewState != ReviewState.Reviewed))
            {
                album = null;
            }
            // 2.对于已登录用户，根据角色判断
            if (userIdStr != null && (!album.IsPublic || album.ReviewState != ReviewState.Reviewed))
            {
                var userId = int.Parse(userIdStr);

                // 管理员可访问任何非公开相册
                if (User.IsInRole("管理员"))
                {
                    //  do nothing...
                }
                else if (User.IsInRole("辅导员"))
                {
                    // 辅导员只可访问自己管理专业下的非公开相册
                    var managedMajors = await _appDbContext.Users
                        .AsNoTracking()
                        .Where(x => x.Id == userId)
                        .Select(x => x.ManagedMajors)
                        .FirstOrDefaultAsync();
                    if (!managedMajors.Any(x => x.Id == album.Class.MajorId))
                    {
                        album = null;
                    }
                }
                else
                {
                    // 其他用户不能访问别人的非公开相册
                    // 此外也不可以访问未通过审核的相册
                    if (album.CreatorId != userId || album.ReviewState != ReviewState.Reviewed)
                    {
                        album = null;
                    }
                }
            }

            if (album == null)
            {
                return BadRequest(new NotExistsError("相册不存在或无权限访问!"));
            }

            var data = new
            {
                album.Id,
                album.CreatorId,
                album.Title,
                album.Description,
                album.IsPublic,
                album.ReviewState,
                LikeCount = await _appDbContext.UserLikeAlbum.CountAsync(x => x.AlbumId == album.Id)
            };
            return Ok(new OkResponse() { Data = data });
        }

        [Authorize]
        [HttpPost("Add")]
        public async Task<IActionResult> AddPersonalAlbum(AddPersonalAlbumParams param)
        {
            var user = await _userManager.GetUserAsync(User);
            if (user.ClassId == null) return BadRequest(new IncorrectError("请先完善班级信息"));
            var item = new PersonalAlbum()
            {
                Title = param.Title,
                Description = param.Description,
                IsPublic = param.IsPublic,
                CreatorId = user.Id,
                ClassId = (int)user.ClassId,
                CreateTime = DateTime.Now
            };
            _appDbContext.PersonalAlbums.Add(item);
            await _appDbContext.SaveChangesAsync();
            return Ok(new OkResponse()
            {
                Data = new
                {
                    item.Id,
                    item.Title,
                    item.Description,
                    item.IsPublic
                }
            });
        }

        [HttpPost("{albumId}/Delete")]
        [Authorize]
        public async Task<IActionResult> DeletePersonalAlbum(int albumId)
        {
            var userId = int.Parse(User.FindFirstValue(ClaimTypes.NameIdentifier));
            var album = await _appDbContext.PersonalAlbums
                .AsNoTracking()
                .Include(x => x.Class)
                .Where(x => x.Id == albumId)
                .FirstOrDefaultAsync();
            if (album == null)
            {
                return BadRequest(new NotExistsError("相册不存在!"));
            }
            //不是本人、不是辅导员、不是管理员
            if (userId != album.CreatorId && !User.IsInRole("管理员") && !User.IsInRole("辅导员"))
            {
                return BadRequest(new IncorrectError("权限不允许"));
            }
            //是辅导员但相册所属的专业不是导员管理的
            if (User.IsInRole("辅导员"))
            {
                var user = await _appDbContext.Users
                    .AsNoTracking()
                    .Include(x => x.ManagedMajors)
                    .Where(x => x.Id == userId).FirstOrDefaultAsync();
                if (!user.ManagedMajors.Any(x => x.Id == album.Class.MajorId))
                {
                    return BadRequest(new IncorrectError("权限不允许"));
                }
            }
            var count = await _appDbContext.Resources.AsNoTracking().CountAsync(x => x.AlbumId == album.Id);
            if (count != 0)
            {
                return BadRequest(new IncorrectError("相册中包含图片、视频或文档，无法删除!"));
            }
            _appDbContext.PersonalAlbums.Remove(album);
            await _appDbContext.SaveChangesAsync();
            return Ok(new OkResponse());
        }

        [HttpPost("Update")]
        [Authorize]
        public async Task<IActionResult> UpdatePersonalAlbum(UpdatePersonalAlbumParam param)
        {
            var userId = int.Parse(User.FindFirstValue(ClaimTypes.NameIdentifier));
            //获取相册
            var personalAlbum = await _appDbContext.PersonalAlbums
                .Where(x => x.Id == param.Id && x.CreatorId == userId)
                .FirstOrDefaultAsync();
            if (null == personalAlbum) return BadRequest(new NotExistsError("相册不存在"));
            personalAlbum.Title = param.Title;
            personalAlbum.IsPublic = param.IsPublic;
            personalAlbum.Description = param.Description;
            personalAlbum.ReviewState = ReviewState.Unreviewed;
            await _appDbContext.SaveChangesAsync();

            return Ok(new OkResponse());
        }

    }
}
